#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2011 OpenWrt.org
# Copyright (C) 2020 Tano Systems LLC, Anton Kikin <a.kikin@tano-systems.com>

USE_PROCD=1
START=50
STOP=05

. $IPKG_INSTROOT/lib/functions.sh

VAR=/var/run/vsftpd
CONF=$VAR/vsftpd.conf

output_field()
{
	local UCI_SECTION=$1
	local KEY=$2
	local INIFIELD=$3
	local DEFVALUE=$4
	local value

	if [ -z "$INIFIELD" ]; then INIFIELD=$KEY; fi

	config_get value "$UCI_SECTION" "$KEY"
	if [ -z "$value" ]; then value=$DEFVALUE; fi

	echo "$INIFIELD=$value" >> $CONF
}

output_bool()
{
	local UCI_SECTION=$1
	local KEY=$2
	local INIFIELD=$3
	local DEFVALUE=$4
	local value

	if [ -z "$INIFIELD" ]; then INIFIELD=$KEY; fi

	config_get value "$UCI_SECTION" "$KEY"
	if [ -z "$value" ]; then value=$DEFVALUE; fi
	if [ x"$value" != x0 ] && [ x"$value" != x1 ]; then value=0; fi

	if [ "$value" == 0 ]; then
		value=NO
	else
		value=YES
	fi

	echo "$INIFIELD=$value" >> $CONF
}

output_const()
{
	local INIFIELD=$1
	local value=$2

	echo "$INIFIELD=$value" >> $CONF
}

get_value()
{
	local UCI_SECTION=$1
	local KEY=$2
	local value

	config_get value "$UCI_SECTION" "$KEY"

	echo $value
}

vusers_iterate()
{
	local config=$1
	local name
	local password
	local owner
	local home
	local _umask
	local maxrate
	local write_enable
	local upload_enable
	local mkdir_enable
	local others_enable

	config_get name "$config" username
	config_get password "$config" password
	config_get home "$config" home
	config_get _umask "$config" "umask"
	config_get maxrate "$config" maxrate
	config_get write_enable "$config" writemkdir
	config_get upload_enable "$config" upload
	config_get others_enable "$config" others

	config_get owner "vuser" username

	rm -f $VUSER_CONF_DIR/$name
	touch $VUSER_CONF_DIR/$name

	if [ -z $home ]; then home=$CHROOT_DIR; fi

	echo "local_root=$home" >> $VUSER_CONF_DIR/$name

	if [ x$write_enable = x1 ]; then write_enable=YES; else write_enable=NO; fi
	if [ x$upload_enable = x1 ]; then upload_enable=YES; else upload_enable=NO; fi
	if [ x$others_enable = x1 ]; then others_enable=YES; else others_enable=NO; fi
	if [ -z $_umask ]; then _umask=022; fi
	if [ -z $maxrate ]; then maxrate=0; fi

	echo "anon_world_readable_only=NO" >> $VUSER_CONF_DIR/$name
	echo "anon_mkdir_write_enable=$write_enable" >> $VUSER_CONF_DIR/$name
	echo "write_enable=$write_enable" >> $VUSER_CONF_DIR/$name
	echo "anon_upload_enable=$upload_enable" >> $VUSER_CONF_DIR/$name
	echo "anon_other_write_enable=$others_enable" >> $VUSER_CONF_DIR/$name
	echo "anon_umask=$_umask" >> $VUSER_CONF_DIR/$name
	echo "anon_max_rate=$maxrate" >> $VUSER_CONF_DIR/$name
	echo "local_max_rate=$maxrate" >> $VUSER_CONF_DIR/$name

	if ! [ -d "$home" ]; then
		mkdir -p $home
		chown $owner:$owner $home
		chmod -R a+w $home
	fi
}

vsftpd_generate_config()
{
	VUSER_DB=$VAR/vusers
	VUSER_CONF_DIR=$VAR/users
	CHROOT_DIR=$VAR/empty

	rm -f $CONF
	rm -rf $VUSER_CONF_DIR $CHROOT_DIR

	mkdir -m 0755 -p $VAR
	mkdir -p $VUSER_CONF_DIR
	mkdir -p $CHROOT_DIR

	enabled=`get_value listen enabled`
	if [ x$enabled = x0 ]; then
		exit 1
	fi

	# listen
	output_const "background" NO
	output_field listen port "listen_port" 21
	output_field listen dataport "ftp_data_port" 20

	# global
	output_bool global 'write' "write_enable" 1
	output_bool global download "download_enable" 1
	output_bool global dirlist "dirlist_enable" 1
	output_bool global lsrecurse "ls_recurse_enable"
	output_bool global dotfile "force_dot_files"
	output_field global 'umask' "local_umask" 022

	banner=`get_value global banner`
	if ! [ -z "$banner" ]; then
		output_const "ftpd_banner" "$banner"
	fi

	chroot_local_user=`get_value global chroot_local_user`
	if [ -z $chroot_local_user ] || [ $chroot_local_user -gt 0 ]; then
		output_const "chroot_local_user" YES
	else
		output_const "chroot_local_user" NO
	fi

	output_bool global dirmessage "dirmessage_enable"
	output_field global dirmsgfile "message_file" ".message"

	# connection
	output_bool connection portmode "port_enable" 1
	output_bool connection pasvmode "pasv_enable" 1
	output_field connection pasvminport "pasv_min_port" 1024
	output_field connection pasvmaxport "pasv_max_port" 65535

	ascii_download_enable=NO
	ascii_upload_enable=NO
	case `get_value connection ascii` in
	download)
		ascii_download_enable=YES
	;;
	upload)
		ascii_upload_enable=YES
	;;
	both)
		ascii_download_enable=YES
		ascii_upload_enable=YES
	esac
	output_const "ascii_download_enable" $ascii_download_enable
	output_const "ascii_upload_enable" $ascii_upload_enable

	output_field connection idletimeout "idle_session_timeout" 1800
	output_field connection conntimeout "connect_timeout" 120
	output_field connection dataconntimeout "data_connection_timeout" 120
	output_field connection maxclient "max_clients" 0
	output_field connection maxperip "max_per_ip" 0
	output_field connection maxrate "local_max_rate" 0

	max_login_fails=`get_value connection maxretry`
	if [ -z $max_login_fails ] || [ $max_login_fails -lt 1 ]; then max_login_fails=3; fi
	output_const "max_login_fails" $max_login_fails

	# anonymous
	ftp_username=`get_value anonymous ftp_username`
	if [ -z $ftp_username ]; then ftp_username="ftp"; fi
	output_const "ftp_username" $ftp_username

	mkdir -m 0755 -p /home/$ftp_username
	chown $ftp_username:$ftp_username /home/$ftp_username

	output_const "anon_world_readable_only" NO

	anon_enable=`get_value anonymous enabled`
	if [ x$anon_enable = x1 ]; then
		anon_root=`get_value anonymous root`
		if [ -z $anon_root ]; then anon_root="/home/ftp"; fi

		output_const "anonymous_enable" YES
		output_const "no_anon_password" YES
		output_const "anon_root" $anon_root
		output_field anonymous 'umask' "anon_umask" 022
		output_field anonymous maxrate "anon_max_rate" 0
		output_bool anonymous writemkdir "anon_mkdir_write_enable" 0
		output_bool anonymous upload "anon_upload_enable" 0
		output_bool anonymous others "anon_other_write_enable" 0

		if ! [ -d "$anon_root" ]; then
			mkdir -p $anon_root
			chown -R $ftp_username:$ftp_username $anon_root
		fi
	else
		output_const "anonymous_enable" NO
	fi

	# log
	output_bool log syslog "syslog_enable" 0
	output_bool log xreflog "xferlog_enable" 0
	output_field log 'file' "vsftpd_log_file" 0

	# users
	vuser_enabled=0
	if [ x`get_value vuser enabled` = x1 ]; then
		vuser_enabled=1

		output_const "guest_enable" YES
		output_field vuser username "guest_username" ftp

		output_const "uci_config_name" vsftpd
		output_const "user_config_dir" "/var/run/vsftpd/users"

		config_foreach vusers_iterate user
	fi

	# local user
	output_const "allow_writeable_chroot" YES
	output_const "secure_chroot_dir" $CHROOT_DIR

	local_root=$(get_value 'local' root)
	if ! [ -z $local_root ]; then
		output_const "local_root" $local_root
	fi

	local_enable=`get_value 'local' enabled`
	if [ x$local_enable = x1 ]; then
		output_const "local_enable" YES
	else
		if [ $vuser_enabled = 1 ]; then
			output_const "local_enable" YES
		else
			output_const "local_enable" NO
		fi
	fi
}

start_service() {
	local enabled4
	local enabled6
	local listen_addr4
	local listen_addr6

	config_load vsftpd

	vsftpd_generate_config

	if ! [ -f $CONF ]; then
		echo "Failed to generate configuration for vsftpd"
		exit 1
	fi

	config_get enabled4 'listen' 'enable4'
	if [ x$enabled4 = x1 ]; then
		config_get listen_addr4 'listen' 'ipv4'

		procd_open_instance
		procd_set_param command /usr/sbin/vsftpd
		procd_append_param command -olisten=YES
		procd_append_param command -olisten_ipv6=NO
		procd_append_param command -olisten_address=${listen_addr4}
		procd_append_param command ${CONF}
		procd_set_param file ${CONF}
		procd_set_param pidfile /var/run/vsftpd-ipv4.pid
		procd_set_param respawn
		procd_set_param stderr 1
		procd_set_param stdout 1
		procd_close_instance
	fi

	config_get enabled6 'listen' 'enable6'
	if [ x$enabled6 = x1 ]; then
		config_get listen_addr6 'listen' 'ipv6'

		procd_open_instance
		procd_set_param command /usr/sbin/vsftpd
		procd_append_param command -olisten=NO
		procd_append_param command -olisten_ipv6=YES
		procd_append_param command -olisten_address6=${listen_addr6}
		procd_append_param command ${CONF}
		procd_set_param file ${CONF}
		procd_set_param pidfile /var/run/vsftpd-ipv6.pid
		procd_set_param respawn
		procd_set_param stderr 1
		procd_set_param stdout 1
		procd_close_instance
	fi
}

service_triggers() {
	procd_add_config_trigger "config.change" "vsftpd" /etc/init.d/vsftpd restart
}
